home *** CD-ROM | disk | FTP | other *** search
/ Skunkware 5 / Skunkware 5.iso / src / X11 / cpicker / Cpick.c < prev    next >
C/C++ Source or Header  |  1995-06-22  |  47KB  |  1,513 lines

  1. /*****************************************************************
  2. Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts,
  3. and the Massachusetts Institute of Technology, Cambridge, Massachusetts.
  4.  
  5.                         All Rights Reserved
  6.  
  7. Permission to use, copy, modify, and distribute this software and its 
  8. documentation for any purpose and without fee is hereby granted, 
  9. provided that the above copyright notice appear in all copies and that
  10. both that copyright notice and this permission notice appear in 
  11. supporting documentation, and that the names of Digital or MIT not be
  12. used in advertising or publicity pertaining to distribution of the
  13. software without specific, written prior permission.  
  14.  
  15. DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
  16. ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
  17. DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
  18. ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
  19. WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
  20. ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
  21. SOFTWARE.
  22.  
  23. ******************************************************************/
  24.  
  25. /*
  26.  * Cpick.c - Color picker widget for Motif Toolkit
  27.  * 
  28.  * Author:    Mike Yang (mikey@sgi.com)
  29.  *        Silicon Graphics, Inc.
  30.  * Date:    Mon Jul 29 1991
  31.  * Copyright (c) 1988, 1991 Mike Yang
  32.  *
  33.  */
  34.  
  35. #include <stdio.h>
  36. #include <math.h>
  37. #include <X11/Xos.h>
  38. #include <Xm/ManagerP.h>
  39. #include "CpickP.h"
  40. #include <Xm/Form.h>
  41. #include <Xm/RowColumn.h>
  42. #include <Xm/Label.h>
  43. #include <Xm/LabelG.h>
  44. #include <Xm/Scale.h>
  45. #include <Xm/Frame.h>
  46. #include <Xm/DrawingA.h>
  47. #include <Xm/PushB.h>
  48. #include <Xm/Text.h>
  49. #include <Xm/TextF.h>
  50. #include <Xm/SelectioB.h>
  51. #include "color.h"
  52. #include <X11/Shell.h>
  53.  
  54. /* #define BUBBLE_MATCH    /* Uses a visible bubble sort when matching colors */
  55.  
  56. #define INCREMENT 10
  57. #define WIDENEAR 8192
  58. #define NARROWNEAR 768
  59. #define MAXIMUM 65536
  60. #define MINIMUM 0
  61. #define MBASE 256
  62. #define RATIO (MAXIMUM/MBASE)
  63. #define FBASE 1000
  64. #define NULLSTR " "
  65. #define RGBFILE "/usr/lib/X11/rgb.txt"
  66.  
  67. /* These should be resources */
  68. #define BORDER_MARGIN        20
  69. #define INTRA_SCALE_SPACING    5
  70. #define SCALE_SPACING        5
  71. #define SCALE_SET_SPACING    20
  72. #define INTER_SPACING        10
  73. #define SCALE_WIDTH        100
  74. #define BOX_MARGIN        10
  75. #define BOX_SHADOW_THICKNESS    4
  76. #define BUTTON_SPACING        4
  77. #define WIDE_STRING        "Wide"
  78. #define RANGE_STRING        "Range"
  79. #define NARROW_STRING        "Narrow"
  80. #define MATCH_STRING        "Match"
  81.  
  82. #define Offset(field) XtOffset(CpickWidget, field)
  83.  
  84. static XtResource resources[] = {
  85.   {XmNhelpProc, XmCCallback, XmRCallback, sizeof(XtPointer),
  86.      Offset(cpick.helpProc), XmRCallback, NULL},
  87.   {XmNokProc, XmCCallback, XmRCallback, sizeof(XtPointer),
  88.      Offset(cpick.okProc), XmRCallback, NULL},
  89.   {XmNselectProc, XmCCallback, XmRCallback, sizeof(XtPointer),
  90.      Offset(cpick.selectProc), XmRCallback, NULL},
  91.   {XmNchangeProc, XmCCallback, XmRCallback, sizeof(XtPointer),
  92.      Offset(cpick.changeProc), XmRCallback, NULL},
  93.   {XmNrestoreProc, XmCCallback, XmRCallback, sizeof(XtPointer),
  94.      Offset(cpick.restoreProc), XmRCallback, NULL},
  95.   {XmNallocated, XmCAllocated, XmRXColor, sizeof(XtPointer),
  96.      Offset(cpick.allocated), XmRXColor, NULL},
  97.   {XmNcmap, XmCCmap, XmRColormap, sizeof(Colormap),
  98.      Offset(cpick.cmap), XmRColormap, NULL},
  99.   {XmNselectLabel, XmCLabel, XmRString, sizeof(String),
  100.      Offset(cpick.selectlabel), XmRString, "Select"},
  101.   {XmNcancelLabel, XmCLabel, XmRString, sizeof(String),
  102.      Offset(cpick.cancellabel), XmRString, "Cancel"},
  103.   {XmNrestoreLabel, XmCLabel, XmRString, sizeof(String),
  104.      Offset(cpick.restorelabel), XmRString, "Restore"},
  105.   {XmNhelpLabel, XmCLabel, XmRString, sizeof(String),
  106.      Offset(cpick.helplabel), XmRString, "Help"},
  107.   {XmNokLabel, XmCLabel, XmRString, sizeof(String),
  108.      Offset(cpick.oklabel), XmRString, "OK"},
  109.   {XmNnearPixels, XmCDimension, XmRDimension, sizeof(Dimension),
  110.      Offset(cpick.nearpixels), XmRString, "64"},
  111.   {XmNuseColors, XmCUsecolors, XmRBoolean, sizeof(Boolean),
  112.      Offset(cpick.usecolors), XmRString, "False"},
  113. };
  114.  
  115. static void ClassInitialize();
  116. static void Initialize();
  117. static void Realize();
  118. static void Resize();
  119. static void Redisplay();
  120. static Boolean SetValues();
  121. static XtGeometryResult GeometryManager();
  122. static void ChangeManaged();
  123.  
  124. static int changeLabel();
  125. static int doNew();
  126. static int doExpose();
  127. static int changePalette();
  128. static int undomatch();
  129. static int matchPalette();
  130. static void setMlabelStr();
  131.  
  132. static void Notify();
  133.  
  134. CpickClassRec cpickClassRec = {
  135.   {
  136.     (WidgetClass) &xmManagerClassRec,    /* superclass          */    
  137.     "Cpick",                /* class_name          */
  138.     sizeof(CpickRec),            /* size              */
  139.     NULL,                /* class_initialize      */
  140.     NULL,                /* class_part_initialize  */
  141.     FALSE,                /* class_inited          */
  142.     Initialize,                /* initialize          */
  143.     NULL,                /* initialize_hook      */
  144.     Realize,                /* realize          */
  145.     NULL,                /* actions          */
  146.     0,                    /* num_actions          */
  147.     resources,                /* resources          */
  148.     XtNumber(resources),        /* resource_count      */
  149.     NULLQUARK,                /* xrm_class          */
  150.     TRUE,                /* compress_motion      */
  151.     TRUE,                /* compress_exposure      */
  152.     TRUE,                /* compress_enterleave    */
  153.     FALSE,                /* visible_interest      */
  154.     NULL,                /* destroy          */
  155.     Resize,                /* resize          */
  156.     XtInheritExpose,            /* expose          */
  157.     SetValues,                /* set_values          */
  158.     NULL,                /* set_values_hook      */
  159.     XtInheritSetValuesAlmost,        /* set_values_almost      */
  160.     NULL,                /* get_values_hook      */
  161.     NULL,                /* accept_focus          */
  162.     XtVersion,                /* version          */
  163.     NULL,                /* callback_private      */
  164.     NULL,                /* tm_table          */
  165.     NULL,                /* query_geometry      */
  166.     XtInheritDisplayAccelerator,    /* display_accelerator      */
  167.     NULL                /* extension          */
  168.   },{
  169. /* composite_class fields */
  170.     /* geometry_handler   */    GeometryManager,
  171.     /* change_managed     */    ChangeManaged,
  172.     /* insert_child      */    XtInheritInsertChild,
  173.     /* delete_child      */    XtInheritDeleteChild,
  174.     /* extension       */   NULL
  175.   },{
  176. /* constraint class record */
  177.     /* no additional resources  */  NULL,
  178.     /* num additional resources */  0,
  179.     /* size of constraint rec   */  0,
  180.     /* constraint_initialize    */  NULL,
  181.     /* constraint_destroy       */  NULL,
  182.     /* constraint_setvalue      */  NULL,
  183.     /* extension                */  NULL,
  184.   },{
  185. /* manager class record */
  186.     XtInheritTranslations,     /* default translations */
  187.     NULL,                    /* syn_resources          */
  188.     0,                 /* num_syn_resources      */
  189.     NULL,                        /* syn_cont_resources     */
  190.     0,                           /* num_syn_cont_resources */
  191.     XmInheritParentProcess,     /* parent_process */
  192.     NULL,                        /* extension              */
  193.   },{
  194. /* Cpick class fields */
  195.     /* empty          */    0,
  196.   }
  197. };
  198.  
  199. WidgetClass cpickWidgetClass = (WidgetClass)&cpickClassRec;
  200.  
  201. typedef unsigned long (*PixProc)();
  202.  
  203. struct vals {
  204.   int ih, iw, x0, y0, rownum;
  205.   PixProc pix;
  206.   CpickWidget cw;
  207. } nval;
  208.  
  209. String colors[] = {"red", "green", "blue",
  210.              "gold", "khaki", "wheat",
  211.              "cyan", "magenta", "yellow"};
  212.  
  213. static char STRING[] = "rgbhsvcmy";
  214.  
  215. static Arg args[20];
  216. static int count;
  217.  
  218. static Position getP(w, s)
  219. Widget w;
  220. String s;
  221. {
  222.   Position result;
  223.   int v;
  224.  
  225.   count = 0;
  226.   XtSetArg(args[count], s, (XtArgVal) &result);  count++;
  227.   XtGetValues(w, args, count);
  228.   v = result;
  229.  
  230.   return(v);
  231. }
  232.  
  233. static Dimension getD(w, s)
  234. Widget w;
  235. String s;
  236. {
  237.   Dimension result;
  238.   int v;
  239.  
  240.   count = 0;
  241.   XtSetArg(args[count], s, (XtArgVal) &result);  count++;
  242.   XtGetValues(w, args, count);
  243.   v = result;
  244.  
  245.   return(v);
  246. }
  247.  
  248. static SetScaleValue(CpickWidget cw, int which, int value)
  249. {
  250.   XmScaleSetValue(cw->cpick.scales[which], value);
  251.   changeLabel(cw, which);
  252. }
  253.  
  254. static SetScaleFloatValue(CpickWidget cw, int which, int value)
  255. {
  256.   XmScaleSetValue(cw->cpick.scales[which], (int) ((FBASE*value)/MBASE));
  257.   changeLabel(cw, which);
  258. }
  259.  
  260. static XtGeometryResult GeometryManager(w, request, reply)
  261.     Widget w;
  262.     XtWidgetGeometry *request;
  263.     XtWidgetGeometry *reply;    /* RETURN */
  264. {
  265.   return XtGeometryYes;
  266. }
  267.  
  268. static void ChangeManaged(cw)
  269. CpickWidget cw;
  270. {
  271.   XtMakeResizeRequest((Widget) cw, getD(cw->cpick.tlevel, XmNwidth),
  272.               getD(cw->cpick.tlevel, XmNheight),
  273.               NULL, NULL);
  274. }
  275.  
  276. static void Realize( gw, valueMask, attributes )
  277.    Widget gw;
  278.    XtValueMask *valueMask;
  279.    XSetWindowAttributes *attributes;
  280. {
  281.   CpickWidget cw = (CpickWidget) gw;
  282.   Dimension newHeight;
  283.  
  284.   XtCreateWindow( gw, InputOutput, (Visual *)CopyFromParent,
  285.          *valueMask, attributes );
  286.   XtRealizeWidget(cw->cpick.tlevel);
  287.  
  288.   count = 0;
  289.   XtSetArg(args[count], XmNheight, &newHeight);  count++;
  290.   XtGetValues(cw->cpick.hexText, args, count);
  291.   if (newHeight > cw->cpick.oldHeight) {
  292.     count = 0;
  293.     XtSetArg(args[count], XmNmarginHeight,
  294.          (newHeight-cw->cpick.oldHeight)/2);  count++;
  295.     XtSetValues(cw->cpick.hexText, args, count);
  296.   }
  297. }
  298.  
  299. static void Resize( gw )
  300.    Widget gw;
  301. {
  302.   CpickWidget cw = (CpickWidget) gw;
  303.  
  304.   XClearWindow( XtDisplay(gw), XtWindow(gw) );
  305.   XtResizeWidget(cw->cpick.tlevel, cw->core.width,
  306.          cw->core.height, (Dimension) 1);
  307.   XClearWindow(XtDisplay(cw->cpick.nlevel), XtWindow(cw->cpick.nlevel) );
  308.   doExpose(cw);
  309. }
  310.  
  311.  
  312. static Boolean SetValues( current, request, desired )
  313.    Widget current,        /* what I am */
  314.           request,        /* what he wants me to be */
  315.           desired;        /* what I will become */
  316. {
  317.   CpickWidget sw = (CpickWidget) desired;
  318.   Boolean redraw = TRUE; /* be stupid for now */
  319.   
  320.   sw->cpick.oldvalue = *(sw->cpick.allocated);
  321.   doNew(sw);
  322.   return(redraw);
  323. }
  324.  
  325. static updateBox(cw)
  326. CpickWidget cw;
  327. {
  328.   XStoreColor(XtDisplay(cw),
  329.           cw->cpick.cmap,
  330.           cw->cpick.allocated);
  331. }
  332.  
  333. void CenterWidget(parent, child)
  334. Widget parent, child;
  335. {
  336.   Position x, y;
  337.  
  338.   x = (getD(parent, XmNwidth) - getD(child, XmNwidth)) / 2;
  339.   y = (getD(parent, XmNheight) - getD(child, XmNheight)) / 2;
  340.   if (x < 0) x = 0;
  341.   XtMoveWidget(child, x, y);
  342. }
  343.  
  344. static char hexDigit(v)
  345. int v;
  346. {
  347.   if (v < 10)
  348.     return '0'+v;
  349.   else
  350.     return 'a'+(v-10);
  351. }
  352.  
  353. static int unhexChar(ch)
  354. char ch;
  355. {
  356.   if (ch >= '0' && ch <= '9')
  357.     return (ch-'0');
  358.   else if (ch >= 'a' && ch <= 'f')
  359.     return (ch-'a'+10);
  360.   else if (ch >= 'A' && ch <= 'F')
  361.     return (ch-'A'+10);
  362.   else
  363.     return -1;
  364. }
  365.  
  366. static Boolean hexChars(s)
  367. char *s;
  368. {
  369.   int each;
  370.  
  371.   for (each=0; each<strlen(s); each++) {
  372.     if (unhexChar(s[each]) == -1)
  373.       return(FALSE);
  374.   }
  375.   return(TRUE);
  376. }
  377.  
  378. static createHex(r, g, b, s)
  379. int r, g, b;
  380. char s[];
  381. {
  382.   sprintf(s, "#%c%c%c%c%c%c",
  383.       hexDigit(256*r/MBASE/16),
  384.       hexDigit(256*r/MBASE % 16),
  385.       hexDigit(256*g/MBASE/16),
  386.       hexDigit(256*g/MBASE % 16),
  387.       hexDigit(256*b/MBASE/16),
  388.       hexDigit(256*b/MBASE % 16));
  389. }
  390.  
  391. static changeRGB(cw, which)
  392. CpickWidget cw;
  393. int which;
  394. {
  395.   RGB rgb;
  396.   HSV hsv;
  397.   CMY cmy;
  398.   char str[13];
  399.  
  400.   if (cw->cpick.matched) {
  401.     setMlabelStr(cw, NULLSTR);
  402.   }
  403.   if (which < H) {
  404.     rgb.r = cw->cpick.values[R]*RATIO;
  405.     rgb.g = cw->cpick.values[G]*RATIO;
  406.     rgb.b = cw->cpick.values[B]*RATIO;
  407.     hsv = RGBToHSV(rgb);
  408.     cw->cpick.values[H] = (int) (hsv.h*(MBASE-1));
  409.     cw->cpick.values[S] = (int) (hsv.s*(MBASE-1));
  410.     cw->cpick.values[V] = (int) (hsv.v*(MBASE-1));
  411.     SetScaleFloatValue(cw, H, cw->cpick.values[H]);
  412.     SetScaleFloatValue(cw, S, cw->cpick.values[S]);
  413.     SetScaleFloatValue(cw, V, cw->cpick.values[V]);
  414.     cmy = RGBToCMY(rgb);
  415.     cw->cpick.values[C] = cmy.c*RATIO/MAXIMUM;
  416.     cw->cpick.values[M] = cmy.m*RATIO/MAXIMUM;
  417.     cw->cpick.values[Y] = cmy.y*RATIO/MAXIMUM;
  418.     SetScaleValue(cw, C, cw->cpick.values[C]);
  419.     SetScaleValue(cw, M, cw->cpick.values[M]);
  420.     SetScaleValue(cw, Y, cw->cpick.values[Y]);
  421.   } else if (which < C) {
  422.     hsv.h = cw->cpick.values[H]/(float) (MBASE-1);
  423.     hsv.s = cw->cpick.values[S]/(float) (MBASE-1);
  424.     hsv.v = cw->cpick.values[V]/(float) (MBASE-1);
  425.     rgb = HSVToRGB(hsv);
  426.     cw->cpick.values[R] = rgb.r*RATIO/MAXIMUM;
  427.     cw->cpick.values[G] = rgb.g*RATIO/MAXIMUM;
  428.     cw->cpick.values[B] = rgb.b*RATIO/MAXIMUM;
  429.     SetScaleValue(cw, R, cw->cpick.values[R]);
  430.     SetScaleValue(cw, G, cw->cpick.values[G]);
  431.     SetScaleValue(cw, B, cw->cpick.values[B]);
  432.     cmy = RGBToCMY(rgb);
  433.     cw->cpick.values[C] = cmy.c*RATIO/MAXIMUM;
  434.     cw->cpick.values[M] = cmy.m*RATIO/MAXIMUM;
  435.     cw->cpick.values[Y] = cmy.y*RATIO/MAXIMUM;
  436.     SetScaleValue(cw, C, cw->cpick.values[C]);
  437.     SetScaleValue(cw, M, cw->cpick.values[M]);
  438.     SetScaleValue(cw, Y, cw->cpick.values[Y]);
  439.   } else {
  440.     cmy.c = cw->cpick.values[C]*RATIO;
  441.     cmy.m = cw->cpick.values[M]*RATIO;
  442.     cmy.y = cw->cpick.values[Y]*RATIO;
  443.     rgb = CMYToRGB(cmy);
  444.     cw->cpick.values[R] = rgb.r*RATIO/MAXIMUM;
  445.     cw->cpick.values[G] = rgb.g*RATIO/MAXIMUM;
  446.     cw->cpick.values[B] = rgb.b*RATIO/MAXIMUM;
  447.     SetScaleValue(cw, R, cw->cpick.values[R]);
  448.     SetScaleValue(cw, G, cw->cpick.values[G]);
  449.     SetScaleValue(cw, B, cw->cpick.values[B]);
  450.     hsv = RGBToHSV(rgb);
  451.     cw->cpick.values[H] = (int) (hsv.h*(MBASE-1));
  452.     cw->cpick.values[S] = (int) (hsv.s*(MBASE-1));
  453.     cw->cpick.values[V] = (int) (hsv.v*(MBASE-1));
  454.     SetScaleFloatValue(cw, H, cw->cpick.values[H]);
  455.     SetScaleFloatValue(cw, S, cw->cpick.values[S]);
  456.     SetScaleFloatValue(cw, V, cw->cpick.values[V]);
  457.   }
  458.   createHex(cw->cpick.values[R], cw->cpick.values[G], cw->cpick.values[B],
  459.         str);
  460.   XmTextFieldSetString(cw->cpick.hexText, str);
  461.   cw->cpick.allocated->red = cw->cpick.values[R]*RATIO;
  462.   cw->cpick.allocated->green = cw->cpick.values[G]*RATIO;
  463.   cw->cpick.allocated->blue = cw->cpick.values[B]*RATIO;
  464.   changePalette(cw, FALSE);
  465.   if (XtIsRealized((Widget) cw) && cw->cpick.changeProc) {
  466.     XtCallCallbacks((Widget) cw, XmNchangeProc,
  467.             (XtPointer) (cw->cpick.allocated));
  468.   }
  469. }
  470.  
  471. static update(cmd, client_data, call_data)
  472.      Widget cmd;
  473.      XtPointer client_data;
  474.      XtPointer call_data;
  475. {
  476.   int which;
  477.   CpickWidget cw = (CpickWidget) client_data;
  478.   XmScaleCallbackStruct *cb = (XmScaleCallbackStruct *) call_data;
  479.  
  480.   cw = (CpickWidget) client_data;
  481.  
  482.   for (which=0; which<NUM; which++) {
  483.     if (cw->cpick.scales[which] == cmd) {
  484.       if (which >= H && which <= V) {
  485.     cw->cpick.values[which] = (cb->value*MBASE)/FBASE;
  486.       } else {
  487.     cw->cpick.values[which] = cb->value;
  488.       }
  489.       changeLabel(cw, which);
  490.       break;
  491.     }
  492.   }
  493.  
  494.   changeRGB(cw, which);
  495.   updateBox(cw);
  496. }
  497.  
  498. static newRGB(cw, r, g, b)
  499. CpickWidget cw;
  500. unsigned short r, g, b;
  501. {
  502.   cw->cpick.values[R] = r/RATIO;
  503.   cw->cpick.values[G] = g/RATIO;
  504.   cw->cpick.values[B] = b/RATIO;
  505.   SetScaleValue(cw, R, cw->cpick.values[R]);
  506.   SetScaleValue(cw, G, cw->cpick.values[G]);
  507.   SetScaleValue(cw, B, cw->cpick.values[B]);
  508.   changeRGB(cw, R);
  509.   updateBox(cw);
  510. }
  511.                   
  512. static changeLabel(cw, which)
  513. CpickWidget cw;
  514. int which;
  515. {
  516.   char str[10];
  517.   XmString xs;
  518.  
  519.   if (which < H || which > V) {
  520.     sprintf(str, "%-5d", cw->cpick.values[which]);
  521.   } else {
  522.     sprintf(str, "%-5.3f", cw->cpick.values[which]/(float) (MBASE-1));
  523.   }
  524.   count = 0;
  525.   xs = XmStringCreateSimple(str);
  526.   XtSetArg(args[count], XmNlabelString, xs);  count++;
  527.   XtSetValues(cw->cpick.labels[which], args, count);
  528. }
  529.  
  530. static createScales(cw)
  531. CpickWidget cw;
  532. {
  533.   int each;
  534.   Widget scaleSet, scale;
  535.   XColor xc, ignore;
  536.   XmString xs, empty, lstring;
  537.   char str[5];
  538.   Dimension height = 0, maxWidth = 0, width;
  539.  
  540.   empty = XmStringCreateSimple(NULLSTR);
  541.   lstring = XmStringCreateSimple("0.000");
  542.  
  543.   count = 0;
  544.   XtSetArg(args[count], XmNtopAttachment, XmATTACH_FORM);  count++;
  545.   XtSetArg(args[count], XmNtopOffset, BORDER_MARGIN);  count++;
  546.   XtSetArg(args[count], XmNleftAttachment, XmATTACH_FORM);  count++;
  547.   XtSetArg(args[count], XmNleftOffset, BORDER_MARGIN);  count++;
  548.   XtSetArg(args[count], XmNbottomAttachment, XmATTACH_FORM);  count++;
  549.   XtSetArg(args[count], XmNbottomOffset, BORDER_MARGIN);  count++;
  550.   XtSetArg(args[count], XmNadjustMargin, False);  count++;
  551.   XtSetArg(args[count], XmNspacing, SCALE_SET_SPACING);  count++;
  552.   XtSetArg(args[count], XmNorientation, XmVERTICAL);  count++;
  553.   XtSetArg(args[count], XmNpacking, XmPACK_COLUMN);  count++;
  554.   cw->cpick.scaleSets = XmCreateRowColumn(cw->cpick.tlevel, "scaleSets",
  555.                       args, count);
  556.   XtManageChild(cw->cpick.scaleSets);
  557.  
  558.   for (each=0; each<NUM; each++) {
  559.     if (each % 3 == 0) {
  560.       count = 0;
  561.       XtSetArg(args[count], XmNadjustMargin, False);  count++;
  562.       XtSetArg(args[count], XmNmarginWidth, 0);  count++;
  563.       XtSetArg(args[count], XmNmarginHeight, 0);  count++;
  564.       XtSetArg(args[count], XmNspacing, SCALE_SPACING);  count++;
  565.       XtSetArg(args[count], XmNorientation, XmVERTICAL);  count++;
  566.       XtSetArg(args[count], XmNpacking, XmPACK_COLUMN);  count++;
  567.       XtSetArg(args[count], XmNentryAlignment, XmALIGNMENT_BEGINNING); count++;
  568.       scaleSet = XmCreateRowColumn(cw->cpick.scaleSets, "scaleSet",
  569.                    args, count);
  570.       XtManageChild(scaleSet);
  571.     }
  572.  
  573.     count = 0;
  574.     XtSetArg(args[count], XmNadjustMargin, False);  count++;
  575.     XtSetArg(args[count], XmNmarginWidth, 0);  count++;
  576.     XtSetArg(args[count], XmNmarginHeight, 0);  count++;
  577.     XtSetArg(args[count], XmNspacing, INTRA_SCALE_SPACING);  count++;
  578.     XtSetArg(args[count], XmNorientation, XmHORIZONTAL);  count++;
  579.     XtSetArg(args[count], XmNpacking, XmPACK_TIGHT);  count++;
  580.     XtSetArg(args[count], XmNentryAlignment, XmALIGNMENT_BEGINNING);  count++;
  581.     scale = XmCreateRowColumn(scaleSet, "scaleGroup", args, count);
  582.     XtManageChild(scale);
  583.     
  584.     count = 0;
  585.     sprintf(str, "%c", STRING[each]);
  586.     xs = XmStringCreateSimple(str);
  587.     XtSetArg(args[count], XmNmarginWidth, 0);  count++;
  588.     XtSetArg(args[count], XmNmarginHeight, 0);  count++;
  589.     XtSetArg(args[count], XmNrecomputeSize, False);  count++;
  590.     XtSetArg(args[count], XmNlabelString, xs);  count++;
  591.     if (cw->cpick.usecolors && ((each < H) || (each > V))) {
  592.       XAllocNamedColor(XtDisplay(cw),
  593.                cw->cpick.cmap,
  594.                colors[each], &xc, &ignore);
  595.       XtSetArg(args[count], XmNforeground, xc.pixel);  count++;
  596.       cw->cpick.names[each] = XmCreateLabel(scale, "name", args, count);
  597.     } else {
  598.       cw->cpick.names[each] = XmCreateLabelGadget(scale, "name", args, count);
  599.     }
  600.     XtManageChild(cw->cpick.names[each]); 
  601.     XmStringFree(xs);
  602.     if (!height) {
  603.       count = 0;
  604.       XtSetArg(args[count], XmNheight, &height);  count++;
  605.       XtGetValues(cw->cpick.names[each], args, count);
  606.     }
  607.     count = 0;
  608.     XtSetArg(args[count], XmNwidth, &width);  count++;
  609.     XtGetValues(cw->cpick.names[each], args, count);
  610.     if (width > maxWidth) {
  611.       maxWidth = width;
  612.     }
  613.  
  614.     count = 0;
  615.     XtSetArg(args[count], XmNwidth, SCALE_WIDTH);  count++;
  616.     XtSetArg(args[count], XmNshowValue, False);  count++;
  617.     XtSetArg(args[count], XmNorientation, XmHORIZONTAL);  count++;
  618.     XtSetArg(args[count], XmNtitleString, empty);  count++;
  619.     XtSetArg(args[count], XmNheight, height);  count++;
  620.     XtSetArg(args[count], XmNminimum, 0);  count++;
  621.     if (each < H || each > V) {
  622.       XtSetArg(args[count], XmNmaximum, MBASE-1);  count++;
  623.     } else {
  624.       XtSetArg(args[count], XmNmaximum, FBASE-1);  count++;
  625.       XtSetArg(args[count], XmNdecimalPoints, 3);  count++;
  626.     }
  627.     cw->cpick.scales[each] = XmCreateScale(scale, "scale", args, count);
  628.     XtManageChild(cw->cpick.scales[each]);
  629.     XtAddCallback(cw->cpick.scales[each], XmNvalueChangedCallback,
  630.           (XtCallbackProc) update, (XtPointer) cw);
  631.     XtAddCallback(cw->cpick.scales[each], XmNdragCallback,
  632.           (XtCallbackProc) update, (XtPointer) cw);
  633.     count = 0;
  634.     XtSetArg(args[count], XmNlabelString, lstring);  count++;
  635.     XtSetArg(args[count], XmNrecomputeSize, False);  count++;
  636.     cw->cpick.labels[each] = XmCreateLabelGadget(scale, "label", args, count);
  637.     XtManageChild(cw->cpick.labels[each]);
  638.   }
  639.  
  640.   count = 0;
  641.   XtSetArg(args[count], XmNwidth, maxWidth);  count++;
  642.   for (each=0; each<NUM; each++) {
  643.     XtSetValues(cw->cpick.names[each], args, count);
  644.   }
  645.   XmStringFree(empty);
  646.   XmStringFree(lstring);
  647. }
  648.  
  649. static void dohex(cmd, client_data, call_data)
  650.      Widget cmd;
  651.      XtPointer client_data;
  652.      XtPointer call_data;
  653. {
  654.   CpickWidget cw = (CpickWidget) client_data;
  655.   char *response, *str;
  656.  
  657.   response = str = XmTextGetString(cw->cpick.hexText);
  658.   if (response[0] == '#') {
  659.     response++;
  660.   }
  661.   if ((strlen(response) != 6 && strlen(response) != 3)
  662.       || !hexChars(response)) {
  663.     setMlabelStr(cw, "Illegal hex string.");
  664.     XBell(XtDisplay(cw), 0);
  665.     cw->cpick.matched = True;
  666.   } else if (strlen(response) == 6) {
  667.     cw->cpick.allocated->red =
  668.       (unhexChar(response[0])*16+unhexChar(response[1]))*RATIO;
  669.     cw->cpick.allocated->green =
  670.       (unhexChar(response[2])*16+unhexChar(response[3]))*RATIO;
  671.     cw->cpick.allocated->blue =
  672.       (unhexChar(response[4])*16+unhexChar(response[5]))*RATIO;
  673.     cw->cpick.keep = FALSE;
  674.     doNew(cw);
  675.   } else if (strlen(response) == 3) {
  676.     cw->cpick.allocated->red = unhexChar(response[0])*16*RATIO;
  677.     cw->cpick.allocated->green = unhexChar(response[1])*16*RATIO;
  678.     cw->cpick.allocated->blue = unhexChar(response[2])*16*RATIO;
  679.     cw->cpick.keep = FALSE;
  680.     doNew(cw);
  681.   }
  682.   XtFree(str);
  683. }
  684.  
  685. static dopalette(cmd, client_data, call_data)
  686.      Widget cmd;
  687.      XtPointer client_data;
  688.      XtPointer call_data;
  689. {
  690.   CpickWidget cw = (CpickWidget) client_data;
  691.   XmString xs;
  692.  
  693.   cw->cpick.wide = (cw->cpick.wide+1) % (RANGE+1);
  694.   if (cw->cpick.wide == WIDE) {
  695.     xs = XmStringCreateSimple(WIDE_STRING);
  696.   } else if (cw->cpick.wide == RANGE) {
  697.     xs = XmStringCreateSimple(RANGE_STRING);
  698.   } else {
  699.     xs = XmStringCreateSimple(NARROW_STRING);
  700.   }
  701.   count = 0;
  702.   XtSetArg(args[count], XmNlabelString, xs);  count++;
  703.   XtSetValues(cw->cpick.paletteButton, args, count);
  704.   XmStringFree(xs);
  705.   changePalette(cw, TRUE);
  706. }
  707.  
  708. static domatch(cmd, client_data, call_data)
  709.      Widget cmd;
  710.      XtPointer client_data;
  711.      XtPointer call_data;
  712. {
  713.   CpickWidget cw = (CpickWidget) client_data;
  714.  
  715.   cw->cpick.matched = TRUE;
  716.   matchPalette(cw);
  717. }
  718.  
  719. static createBox(cw)
  720. CpickWidget cw;
  721. {
  722.   Widget match;
  723.   XmString xs;
  724.  
  725.   count = 0;
  726.   XtSetArg(args[count], XmNadjustMargin, False);  count++;
  727.   XtSetArg(args[count], XmNmarginWidth, 0);  count++;
  728.   XtSetArg(args[count], XmNmarginHeight, 0);  count++;
  729.   XtSetArg(args[count], XmNtopAttachment, XmATTACH_FORM);  count++;
  730.   XtSetArg(args[count], XmNtopOffset, BORDER_MARGIN);  count++;
  731.   XtSetArg(args[count], XmNrightAttachment, XmATTACH_FORM);  count++;
  732.   XtSetArg(args[count], XmNrightOffset, BORDER_MARGIN);  count++;
  733.   XtSetArg(args[count], XmNorientation, XmVERTICAL);  count++;
  734.   XtSetArg(args[count], XmNpacking, XmPACK_COLUMN);  count++;
  735.   XtSetArg(args[count], XmNentryAlignment, XmALIGNMENT_CENTER);  count++;
  736.   XtSetArg(args[count], XmNspacing, BUTTON_SPACING);  count++;
  737.   cw->cpick.boxButtons = XmCreateRowColumn(cw->cpick.tlevel, "boxButtons",
  738.                        args, count);
  739.   XtManageChild(cw->cpick.boxButtons);
  740.   
  741.   count = 0;
  742.   XtSetArg(args[count], XmNcolumns, 8);  count++;
  743.   XtSetArg(args[count], XmNmarginHeight, 0);  count++;
  744.   cw->cpick.hexText = XmCreateTextField(cw->cpick.boxButtons, "hexText",
  745.                     args, count);
  746.   XtManageChild(cw->cpick.hexText);
  747.   XtAddCallback(cw->cpick.hexText, XmNactivateCallback,
  748.         (XtCallbackProc) dohex, (XtPointer) cw);
  749.   count = 0;
  750.   XtSetArg(args[count], XmNheight, &cw->cpick.oldHeight);  count++;
  751.   XtGetValues(cw->cpick.hexText, args, count);
  752.  
  753.   count = 0;
  754.   xs = XmStringCreateSimple(RANGE_STRING);
  755.   XtSetArg(args[count], XmNlabelString, xs);  count++;
  756.   XtSetArg(args[count], XmNrecomputeSize, False);  count++;
  757.   XtSetArg(args[count], XmNmarginLeft, 0);  count++;
  758.   XtSetArg(args[count], XmNmarginRight, 0);  count++;
  759.   XtSetArg(args[count], XmNmarginTop, 0);  count++;
  760.   XtSetArg(args[count], XmNmarginBottom, 0);  count++;
  761.   cw->cpick.paletteButton = XmCreatePushButton(cw->cpick.boxButtons,
  762.                            "paletteButton", args, count);
  763.   XtManageChild(cw->cpick.paletteButton);
  764.   XmStringFree(xs);
  765.   XtAddCallback(cw->cpick.paletteButton, XmNactivateCallback,
  766.         (XtCallbackProc) dopalette, (XtPointer) cw);
  767.  
  768.   count = 0;
  769.   xs = XmStringCreateSimple(MATCH_STRING);
  770.   XtSetArg(args[count], XmNlabelString, xs);  count++;
  771.   XtSetArg(args[count], XmNrecomputeSize, False);  count++;
  772.   XtSetArg(args[count], XmNmarginLeft, 0);  count++;
  773.   XtSetArg(args[count], XmNmarginRight, 0);  count++;
  774.   XtSetArg(args[count], XmNmarginTop, 0);  count++;
  775.   XtSetArg(args[count], XmNmarginBottom, 0);  count++;
  776.   cw->cpick.matchButton = XmCreatePushButton(cw->cpick.boxButtons,
  777.                          "matchButton", args, count);
  778.   XtManageChild(cw->cpick.matchButton);
  779.   XmStringFree(xs);
  780.   XtAddCallback(cw->cpick.matchButton, XmNactivateCallback,
  781.         (XtCallbackProc) domatch, (XtPointer) cw);
  782.  
  783.   count = 0;
  784.   XtSetArg(args[count], XmNtopAttachment, XmATTACH_FORM);  count++;
  785.   XtSetArg(args[count], XmNtopOffset, BORDER_MARGIN);  count++;
  786.   XtSetArg(args[count], XmNleftAttachment, XmATTACH_WIDGET);  count++;
  787.   XtSetArg(args[count], XmNleftWidget, cw->cpick.scaleSets);  count++;
  788.   XtSetArg(args[count], XmNleftOffset, INTER_SPACING);  count++;
  789.   XtSetArg(args[count], XmNrightAttachment, XmATTACH_WIDGET);  count++;
  790.   XtSetArg(args[count], XmNrightWidget, cw->cpick.boxButtons);  count++;
  791.   XtSetArg(args[count], XmNrightOffset, INTER_SPACING);  count++;
  792.   XtSetArg(args[count], XmNshadowType, XmSHADOW_IN);  count++;
  793.   XtSetArg(args[count], XmNmarginWidth, BOX_MARGIN);  count++;
  794.   XtSetArg(args[count], XmNmarginHeight, BOX_MARGIN);  count++;
  795.   cw->cpick.bcontainer = XmCreateFrame(cw->cpick.tlevel, "bcontainer",
  796.                        args, count);
  797.   XtManageChild(cw->cpick.bcontainer);
  798.  
  799.   count = 0;
  800.   XtSetArg(args[count], XmNshadowType, XmSHADOW_OUT);  count++;
  801.   XtSetArg(args[count], XmNshadowThickness, BOX_SHADOW_THICKNESS);  count++;
  802.   cw->cpick.bframe = XmCreateFrame(cw->cpick.bcontainer, "bframe",
  803.                    args, count);
  804.   XtManageChild(cw->cpick.bframe);
  805.  
  806.   count = 0;
  807.   cw->cpick.box = XmCreateDrawingArea(cw->cpick.bframe, "box", args, count);
  808.   XtManageChild(cw->cpick.box);
  809. }
  810.  
  811. static doNew(cw)
  812. CpickWidget cw;
  813. {
  814.   newRGB(cw,
  815.      cw->cpick.allocated->red,
  816.      cw->cpick.allocated->green,
  817.      cw->cpick.allocated->blue);
  818.   if (cw->cpick.box) {
  819.     count = 0;
  820.     XtSetArg(args[count], XmNbackground, cw->cpick.allocated->pixel);  count++;
  821.     XtSetValues(cw->cpick.box, args, count);
  822.   }
  823. }
  824.  
  825. static nButtonHandler(w, val, event)
  826. Widget w;
  827. struct vals *val;
  828. XButtonEvent *event;
  829. {
  830.   int newpix, v;
  831.   XColor xc;
  832.   CpickWidget cw = val->cw;
  833.  
  834.   if (!val->ih || !val->iw) {
  835.     return;
  836.   }
  837.  
  838.   v = (event->x-val->x0)/val->iw + ((event->y-val->y0)/val->ih)*val->rownum;
  839.   newpix = val->pix(cw, v);
  840.   if (newpix != MAXIMUM) {
  841.     xc.pixel = newpix;
  842.     XQueryColor(XtDisplay(cw), cw->cpick.cmap, &xc);
  843.     cw->cpick.allocated->red = xc.red;
  844.     cw->cpick.allocated->green = xc.green;
  845.     cw->cpick.allocated->blue = xc.blue;
  846.     cw->cpick.keep = TRUE;
  847.     doNew(cw);
  848.     if (cw->cpick.matched) {
  849.       setMlabelStr(cw, cw->cpick.mnames[v]);
  850.     }
  851.   }
  852. }
  853.  
  854. static unsigned long nPixel(cw, each)
  855. CpickWidget cw;
  856. int each;
  857. {
  858.   if (each < cw->cpick.nearpixels)
  859.     return cw->cpick.nearcells[each].pixel;
  860.   else
  861.     return MAXIMUM;
  862. }
  863.  
  864. static createGrid(wid, num, x0, y0, h, w, proc, val, pix)
  865. Widget wid;
  866. int num;
  867. Position x0, y0;
  868. Dimension h, w;
  869. XtEventHandler proc;
  870. struct vals *val;
  871. PixProc pix;
  872. {
  873.   int each, x, y, hs, ws;
  874.   double hsize, wsize;
  875.   GC gc;
  876.   XGCValues gcv;
  877.   unsigned long black;
  878.  
  879.   val->pix = pix;
  880.  
  881.   hsize = sqrt((double) num*VNEARRATIO/HNEARRATIO);
  882.   wsize = ceil(hsize*HNEARRATIO/VNEARRATIO);
  883.   hsize = ceil(hsize);
  884.  
  885.   val->ih = (int) ((h-1)/hsize);
  886.   val->iw = (int) ((w-1)/wsize);
  887.   val->rownum = (int) wsize;
  888.   hs = (int) hsize*val->ih+1;
  889.   ws = (int) wsize*val->iw+1;
  890.  
  891. /*
  892.   XtMoveWidget(wid, (Position) x0, (Position) y0);
  893.   XtResizeWidget(wid, w, h, (Dimension) 1);
  894. */
  895.  
  896.   val->y0 = (h-hs)/2;
  897.   val->x0 = (w-ws)/2;
  898.  
  899.   gcv.function = GXcopy;
  900.   gcv.fill_style = FillSolid;
  901.   black = XBlackPixel(XtDisplay(wid),
  902.               XDefaultScreen(XtDisplay(wid)));
  903.   gcv.background = black;
  904.   gc = XCreateGC(XtDisplay(wid), XtWindow(wid),
  905.          GCBackground | GCFunction | GCFillStyle, &gcv);
  906.  
  907.   XSync(XtDisplay(wid),0);
  908.   for (each=0; each<num; each++) {
  909.     x = (each % val->rownum)*val->iw;
  910.     y = (each/val->rownum)*val->ih;
  911.     XSetForeground(XtDisplay(wid), gc, pix(val->cw, each));
  912.     XFillRectangle(XtDisplay(wid), XtWindow(wid), gc, val->x0+x, val->y0+y,
  913.            val->iw, val->ih);
  914.     XSetForeground(XtDisplay(wid), gc, black);
  915.     XDrawRectangle(XtDisplay(wid), XtWindow(wid), gc, val->x0+x, val->y0+y,
  916.            val->iw, val->ih);
  917.   }
  918.  
  919.   XtAddEventHandler(wid, ButtonPressMask, FALSE, (XtEventHandler) proc,
  920.             (XtPointer) val);
  921.   XFreeGC(XtDisplay(wid), gc);
  922. }
  923.  
  924. static doExpose(cw)
  925. CpickWidget cw;
  926. {
  927.   nval.cw = cw;
  928.   createGrid(cw->cpick.nlevel, (int) cw->cpick.nearpixels,
  929.          getP(cw->cpick.nlevel, XmNx),
  930.          getP(cw->cpick.nlevel, XmNy),
  931.          getD(cw->cpick.nlevel, XmNheight),
  932.          getD(cw->cpick.nlevel, XmNwidth),
  933.          nButtonHandler, &nval, nPixel);
  934. }
  935.  
  936. static nlevel_expose(w, client_data, call_data)
  937.      Widget w;
  938.      XtPointer client_data;
  939.      XtPointer call_data;
  940. {
  941.   XEvent ev;
  942.   CpickWidget cw = (CpickWidget) client_data;
  943.  
  944.   XFlush(XtDisplay(w));
  945.   while (XCheckWindowEvent(XtDisplay(w), XtWindow(w), ExposureMask, &ev)) {
  946.     /* eat it */
  947.   }
  948.   
  949.   doExpose(cw);
  950. }
  951.  
  952. static doselect(cmd, client_data, call_data)
  953.      Widget cmd;
  954.      XtPointer client_data;
  955.      XtPointer call_data;
  956. {
  957.   CpickWidget cw = (CpickWidget) client_data;
  958.  
  959.   undomatch(cw);
  960.   if (cw->cpick.selectProc) {
  961.     XtCallCallbacks((Widget) cw, XmNselectProc,
  962.             (XtPointer)(cw->cpick.allocated));
  963.   }
  964. }
  965.  
  966. static docancel(cmd, client_data, call_data)
  967.      Widget cmd;
  968.      XtPointer client_data;
  969.      XtPointer call_data;
  970. {
  971.   CpickWidget cw = (CpickWidget) client_data;
  972.  
  973.   *(cw->cpick.allocated) = cw->cpick.oldvalue;
  974.   doNew(cw);
  975. }
  976.  
  977. static dorestore(cmd, client_data, call_data)
  978.      Widget cmd;
  979.      XtPointer client_data;
  980.      XtPointer call_data;
  981. {
  982.   CpickWidget cw = (CpickWidget) client_data;
  983.  
  984.   if (cw->cpick.restoreProc) {
  985.     XtCallCallbacks((Widget) cw, XmNrestoreProc,
  986.             (XtPointer)(cw->cpick.allocated));
  987.   }
  988.   changePalette(cw, TRUE);
  989. }
  990.  
  991. static dook(cmd, client_data, call_data)
  992.      Widget cmd;
  993.      XtPointer client_data;
  994.      XtPointer call_data;
  995. {
  996.   CpickWidget cw = (CpickWidget) client_data;
  997.  
  998.   if (cw->cpick.okProc) {
  999.     XtCallCallbacks((Widget) cw, XmNokProc,
  1000.             (XtPointer)(cw->cpick.allocated));
  1001.   }
  1002. }
  1003.  
  1004. static dohelp(cmd, client_data, call_data)
  1005.      Widget cmd;
  1006.      XtPointer client_data;
  1007.      XtPointer call_data;
  1008. {
  1009.   CpickWidget cw = (CpickWidget) client_data;
  1010.  
  1011.   if (cw->cpick.helpProc) {
  1012.     XtCallCallbacks((Widget) cw, XmNhelpProc,
  1013.             (XtPointer)(cw->cpick.allocated));
  1014.   }
  1015. }
  1016.  
  1017. static createCommands(cw)
  1018. CpickWidget cw;
  1019. {
  1020.   Widget buffer;
  1021.   XmString xs;
  1022.  
  1023.   count = 0;
  1024.   XtSetArg(args[count], XmNadjustMargin, False);  count++;
  1025.   XtSetArg(args[count], XmNmarginWidth, 0);  count++;
  1026.   XtSetArg(args[count], XmNmarginHeight, 0);  count++;
  1027.   XtSetArg(args[count], XmNrightAttachment, XmATTACH_FORM);  count++;
  1028.   XtSetArg(args[count], XmNrightOffset, BORDER_MARGIN);  count++;
  1029.   XtSetArg(args[count], XmNbottomAttachment, XmATTACH_FORM);  count++;
  1030.   XtSetArg(args[count], XmNbottomOffset, BORDER_MARGIN);  count++;
  1031.   XtSetArg(args[count], XmNorientation, XmHORIZONTAL);  count++;
  1032.   XtSetArg(args[count], XmNpacking, XmPACK_COLUMN);  count++;
  1033.   XtSetArg(args[count], XmNentryAlignment, XmALIGNMENT_CENTER);  count++;
  1034.   XtSetArg(args[count], XmNspacing, BUTTON_SPACING);  count++;
  1035.   cw->cpick.commandBox = XmCreateRowColumn(cw->cpick.tlevel, "commandBox",
  1036.                        args, count);
  1037.   XtManageChild(cw->cpick.commandBox);
  1038.  
  1039.   count = 0;
  1040.   XtSetArg(args[count], XmNleftAttachment, XmATTACH_WIDGET);  count++;
  1041.   XtSetArg(args[count], XmNleftWidget, cw->cpick.scaleSets);  count++;
  1042.   XtSetArg(args[count], XmNleftOffset, INTER_SPACING);  count++;
  1043.   XtSetArg(args[count], XmNrightAttachment, XmATTACH_WIDGET);  count++;
  1044.   XtSetArg(args[count], XmNrightWidget, cw->cpick.commandBox);  count++;
  1045.   XtSetArg(args[count], XmNwidth, 1);  count++;
  1046.   buffer = XmCreateDrawingArea(cw->cpick.tlevel, "commandBuffer", args, count);
  1047.   XtManageChild(buffer);
  1048.  
  1049.   if (cw->cpick.selectlabel) {
  1050.     count = 0;
  1051.     xs = XmStringCreateSimple(cw->cpick.selectlabel);
  1052.     XtSetArg(args[count], XmNlabelString, xs);  count++;
  1053.     XtSetArg(args[count], XmNmarginLeft, 0);  count++;
  1054.     XtSetArg(args[count], XmNmarginRight, 0);  count++;
  1055.     XtSetArg(args[count], XmNmarginTop, 0);  count++;
  1056.     XtSetArg(args[count], XmNmarginBottom, 0);  count++;
  1057.     cw->cpick.select0 = XmCreatePushButton(cw->cpick.commandBox, "select",
  1058.                        args, count);
  1059.     XtManageChild(cw->cpick.select0);
  1060.     XtAddCallback(cw->cpick.select0, XmNactivateCallback,
  1061.           (XtCallbackProc) doselect, (XtPointer) cw);
  1062.     XmStringFree(xs);
  1063.   }
  1064.   if (cw->cpick.cancellabel) {
  1065.     count = 0;
  1066.     xs = XmStringCreateSimple(cw->cpick.cancellabel);
  1067.     XtSetArg(args[count], XmNlabelString, xs);  count++;
  1068.     XtSetArg(args[count], XmNmarginLeft, 0);  count++;
  1069.     XtSetArg(args[count], XmNmarginRight, 0);  count++;
  1070.     XtSetArg(args[count], XmNmarginTop, 0);  count++;
  1071.     XtSetArg(args[count], XmNmarginBottom, 0);  count++;
  1072.     cw->cpick.cancel = XmCreatePushButton(cw->cpick.commandBox, "cancel",
  1073.                       args, count);
  1074.     XtManageChild(cw->cpick.cancel);
  1075.     XtAddCallback(cw->cpick.cancel, XmNactivateCallback,
  1076.           (XtCallbackProc) docancel, (XtPointer) cw);
  1077.     XmStringFree(xs);
  1078.   }
  1079.   if (cw->cpick.restorelabel) {
  1080.     count = 0;
  1081.     xs = XmStringCreateSimple(cw->cpick.restorelabel);
  1082.     XtSetArg(args[count], XmNlabelString, xs);  count++;
  1083.     XtSetArg(args[count], XmNmarginLeft, 0);  count++;
  1084.     XtSetArg(args[count], XmNmarginRight, 0);  count++;
  1085.     XtSetArg(args[count], XmNmarginTop, 0);  count++;
  1086.     XtSetArg(args[count], XmNmarginBottom, 0);  count++;
  1087.     cw->cpick.restore = XmCreatePushButton(cw->cpick.commandBox, "restore",
  1088.                        args, count);
  1089.     XtManageChild(cw->cpick.restore);
  1090.     XtAddCallback(cw->cpick.restore, XmNactivateCallback,
  1091.           (XtCallbackProc) dorestore, (XtPointer) cw);
  1092.     XmStringFree(xs);
  1093.   }
  1094.   if (cw->cpick.oklabel) {
  1095.     count = 0;
  1096.     xs = XmStringCreateSimple(cw->cpick.oklabel);
  1097.     XtSetArg(args[count], XmNlabelString, xs);  count++;
  1098.     XtSetArg(args[count], XmNmarginLeft, 0);  count++;
  1099.     XtSetArg(args[count], XmNmarginRight, 0);  count++;
  1100.     XtSetArg(args[count], XmNmarginTop, 0);  count++;
  1101.     XtSetArg(args[count], XmNmarginBottom, 0);  count++;
  1102.     cw->cpick.ok = XmCreatePushButton(cw->cpick.commandBox, "ok",
  1103.                       args, count);
  1104.     XtManageChild(cw->cpick.ok);
  1105.     XtAddCallback(cw->cpick.ok, XmNactivateCallback,
  1106.           (XtCallbackProc) dook, (XtPointer) cw);
  1107.     XmStringFree(xs);
  1108.   }
  1109.   if (cw->cpick.helplabel) {
  1110.     count = 0;
  1111.     xs = XmStringCreateSimple(cw->cpick.helplabel);
  1112.     XtSetArg(args[count], XmNlabelString, xs);  count++;
  1113.     XtSetArg(args[count], XmNmarginLeft, 0);  count++;
  1114.     XtSetArg(args[count], XmNmarginRight, 0);  count++;
  1115.     XtSetArg(args[count], XmNmarginTop, 0);  count++;
  1116.     XtSetArg(args[count], XmNmarginBottom, 0);  count++;
  1117.     cw->cpick.help = XmCreatePushButton(cw->cpick.commandBox, "help",
  1118.                       args, count);
  1119.     XtManageChild(cw->cpick.help);
  1120.     XtAddCallback(cw->cpick.help, XmNactivateCallback,
  1121.           (XtCallbackProc) dohelp, (XtPointer) cw);
  1122.     XmStringFree(xs);
  1123.   }
  1124.  
  1125.   count = 0;
  1126.   XtSetArg(args[count], XmNleftAttachment, XmATTACH_WIDGET);  count++;
  1127.   XtSetArg(args[count], XmNleftWidget, cw->cpick.scaleSets);  count++;
  1128.   XtSetArg(args[count], XmNleftOffset, INTER_SPACING);  count++;
  1129.   XtSetArg(args[count], XmNrightAttachment, XmATTACH_FORM);  count++;
  1130.   XtSetArg(args[count], XmNrightOffset, BORDER_MARGIN);  count++;
  1131.   XtSetArg(args[count], XmNbottomAttachment, XmATTACH_WIDGET);  count++;
  1132.   XtSetArg(args[count], XmNbottomWidget, cw->cpick.commandBox);  count++;
  1133.   XtSetArg(args[count], XmNbottomOffset, INTER_SPACING);  count++;
  1134.   cw->cpick.mframe = XmCreateFrame(cw->cpick.tlevel, "mframe", args, count);
  1135.   XtManageChild(cw->cpick.mframe);
  1136.  
  1137.   count = 0;
  1138.   xs = XmStringCreateSimple(NULLSTR);
  1139.   XtSetArg(args[count], XmNlabelString, xs);  count++;
  1140.   XtSetArg(args[count], XmNalignment, XmALIGNMENT_CENTER);  count++;
  1141.   XtSetArg(args[count], XmNrecomputeSize, False);  count++;
  1142.   cw->cpick.mlabel = XmCreateLabel(cw->cpick.mframe, "mlabel", args, count);
  1143.   XtManageChild(cw->cpick.mlabel);
  1144.   XmStringFree(xs);
  1145.   cw->cpick.matched = FALSE;
  1146. }
  1147.  
  1148. static initPalette(cw)
  1149. CpickWidget cw;
  1150. {
  1151.   unsigned long cells[MAXPIXELS];
  1152.   int each;
  1153.  
  1154.   if (!XAllocColorCells(XtDisplay(cw), cw->cpick.cmap, FALSE, NULL, 0,
  1155.             cells, (int) cw->cpick.nearpixels)) {
  1156.     fprintf(stderr, "Cpick: Can't allocate %d cells for palette.\n", (int) cw->cpick.nearpixels);
  1157.     exit(1);
  1158.   }
  1159.   for (each=0; each<(int) cw->cpick.nearpixels; each++) {
  1160.     cw->cpick.nearcells[each].pixel = cells[each];
  1161.     cw->cpick.nearcells[each].flags = DoRed | DoGreen | DoBlue;
  1162.   }
  1163.   changePalette(cw, TRUE);
  1164. }
  1165.  
  1166. static changePalette(cw, new)
  1167. CpickWidget cw;
  1168. Boolean new;
  1169. {
  1170.   int each, each2, r, g, b, nr, ng, nb, eachr, eachg, eachb;
  1171.   int delta, halfr, halfg, halfb, near;
  1172.   double hueinc;
  1173.   RGB rgb;
  1174.   HSV hsv;
  1175.   int mods[MAXPIXELS][3], nummods;
  1176.  
  1177.   if (new) {
  1178.     undomatch(cw);
  1179.   }
  1180.   if (cw->cpick.keep) {
  1181.     cw->cpick.keep = FALSE;
  1182.   } else {
  1183.     if (cw->cpick.wide == NARROW) {
  1184.       halfr = halfg = halfb = (int) cw->cpick.nearpixels/2;
  1185.       r = cw->cpick.allocated->red;
  1186.       g = cw->cpick.allocated->green;
  1187.       b = cw->cpick.allocated->blue;
  1188.  
  1189.       for (each=0; each<(int) cw->cpick.nearpixels/2; each++) {
  1190.     if (r-halfr*NARROWNEAR < 0)
  1191.       halfr--;
  1192.     if (r+((int) cw->cpick.nearpixels-1-halfr)*NARROWNEAR >= MAXIMUM)
  1193.       halfr++;
  1194.     if (g-halfg*NARROWNEAR < 0)
  1195.       halfg--;
  1196.     if (g+((int) cw->cpick.nearpixels-1-halfg)*NARROWNEAR >= MAXIMUM)
  1197.       halfg++;
  1198.     if (b-halfb*NARROWNEAR < 0)
  1199.       halfb--;
  1200.     if (b+((int) cw->cpick.nearpixels-1-halfb)*NARROWNEAR >= MAXIMUM)
  1201.       halfb++;
  1202.       }
  1203.  
  1204.       halfb = halfg = halfr = (halfr+halfg+halfb)/3;
  1205.       for (each=0; each<(int) cw->cpick.nearpixels; each++) {
  1206.     nr = r+(each-halfr)*NARROWNEAR;
  1207.     ng = g+(each-halfg)*NARROWNEAR;
  1208.     nb =  b+(each-halfb)*NARROWNEAR;
  1209.     if (nr < 0)
  1210.       nr = 0;
  1211.     if (ng < 0)
  1212.       ng = 0;
  1213.     if (nb < 0)
  1214.       nb = 0;
  1215.     if (nr >= MAXIMUM)
  1216.       nr = MAXIMUM-1;
  1217.     if (ng >= MAXIMUM)
  1218.       ng = MAXIMUM-1;
  1219.     if (nb >= MAXIMUM)
  1220.       nb = MAXIMUM-1;
  1221.     cw->cpick.nearcells[each].red = nr;
  1222.     cw->cpick.nearcells[each].green = ng;
  1223.     cw->cpick.nearcells[each].blue = nb;
  1224.       }
  1225.       XStoreColors(XtDisplay(cw), cw->cpick.cmap, cw->cpick.nearcells,
  1226.            (int) cw->cpick.nearpixels);
  1227.     } else if (cw->cpick.wide == WIDE) {
  1228.       near = WIDENEAR;
  1229.       delta = (int) exp(log((double) cw->cpick.nearpixels)/3.0);
  1230.       halfr = halfg = halfb = delta/2;
  1231.  
  1232.       r = cw->cpick.allocated->red;
  1233.       g = cw->cpick.allocated->green;
  1234.       b = cw->cpick.allocated->blue;
  1235.  
  1236.       for (each=0; each<delta/2; each++) {
  1237.     if (r-halfr*near < 0)
  1238.       halfr--;
  1239.     if (r+(delta-1-halfr)*near >= MAXIMUM)
  1240.       halfr++;
  1241.     if (g-halfg*near < 0)
  1242.       halfg--;
  1243.     if (g+(delta-1-halfg)*near >= MAXIMUM)
  1244.       halfg++;
  1245.     if (b-halfb*near < 0)
  1246.       halfb--;
  1247.     if (b+(delta-1-halfb)*near >= MAXIMUM)
  1248.       halfb++;
  1249.       }
  1250.  
  1251.       nummods = 0;
  1252.       for (eachb=0; eachb<delta; eachb++) {
  1253.     for (eachg=0; eachg<delta; eachg++) {
  1254.       for (eachr=0; eachr<(int) cw->cpick.nearpixels/(delta*delta); eachr++) {
  1255.         mods[nummods][R] = eachr-halfr;
  1256.         mods[nummods][G] = eachg-halfg;
  1257.         mods[nummods][B] = eachb-halfb;
  1258.         nummods++;
  1259.       }
  1260.     }
  1261.       }
  1262.       for (each=0; each<nummods-1; each++) {
  1263.     for (each2=each+1; each2<nummods; each2++) {
  1264.       if (mods[each][R]+mods[each][G]+mods[each][B] >
  1265.           mods[each2][R]+mods[each2][G]+mods[each2][B]) {
  1266.         eachr = mods[each][R];
  1267.         eachg = mods[each][G];
  1268.         eachb = mods[each][B];
  1269.         mods[each][R] = mods[each2][R];
  1270.         mods[each][G] = mods[each2][G];
  1271.         mods[each][B] = mods[each2][B];
  1272.         mods[each2][R] = eachr;
  1273.         mods[each2][G] = eachg;
  1274.         mods[each2][B] = eachb;
  1275.       }
  1276.     }
  1277.       }
  1278.  
  1279.       for (each=0; each<nummods; each++) {
  1280.     cw->cpick.nearcells[each].red = r+mods[each][R]*near;
  1281.     cw->cpick.nearcells[each].green = g+mods[each][G]*near;
  1282.     cw->cpick.nearcells[each].blue = b+mods[each][B]*near;
  1283.       }
  1284.       XStoreColors(XtDisplay(cw), cw->cpick.cmap, cw->cpick.nearcells,
  1285.            (int) cw->cpick.nearpixels);
  1286.     } else if (new) {
  1287.       hueinc = 1.0/cw->cpick.nearpixels;
  1288.       hsv.s = hsv.v = 1.0;
  1289.       hsv.h = 0.0;
  1290.       for (each=0; each<(int) cw->cpick.nearpixels; each++) {
  1291.     rgb = HSVToRGB(hsv);
  1292.     cw->cpick.nearcells[each].red = rgb.r;
  1293.     cw->cpick.nearcells[each].green = rgb.g;
  1294.     cw->cpick.nearcells[each].blue = rgb.b;
  1295.     hsv.h = hsv.h + hueinc;
  1296.       }
  1297.       XStoreColors(XtDisplay(cw), cw->cpick.cmap, cw->cpick.nearcells,
  1298.            (int) cw->cpick.nearpixels);
  1299.     }
  1300.   }
  1301. }
  1302.  
  1303. static undomatch(cw)
  1304. CpickWidget cw;
  1305. {
  1306.   XmString xs;
  1307.  
  1308.   if (cw->cpick.matched) {
  1309.     cw->cpick.matched = FALSE;
  1310.     setMlabelStr(cw, NULLSTR);
  1311.   }
  1312. }
  1313.  
  1314. static matchPalette(cw)
  1315. CpickWidget cw;
  1316. {
  1317.   int each, each2, ct, r, g, b, nr, ng, nb, cr, cg, cb, d;
  1318.   FILE *fd;
  1319.   char name[MAXNAME], *sname;
  1320.  
  1321.   for (each=0; each<MAXPIXELS; each++) {
  1322.     strcpy(cw->cpick.mnames[each], NULLSTR);
  1323.     cw->cpick.mdist[each] = MBASE*MBASE*3;
  1324.   }
  1325.   cr = cw->cpick.allocated->red/RATIO;
  1326.   cg = cw->cpick.allocated->green/RATIO;
  1327.   cb = cw->cpick.allocated->blue/RATIO;
  1328.   fd = fopen(RGBFILE, "r");
  1329.   if (fd == NULL || feof(fd)) {
  1330.     undomatch(cw);
  1331.   } else {
  1332.     ct = 0;
  1333.     r = g = b = -1;
  1334.     while (!feof(fd)) {
  1335.       fscanf(fd, "%d %d %d", &nr, &ng, &nb);
  1336.       fgets(name, MAXNAME, fd);
  1337.       name[strlen(name)-1] = '\0';
  1338.       sname = name;
  1339.       while (sname[0] == ' ' || sname[0] == '\t') {
  1340.     sname++;
  1341.       }
  1342.       if (nr != r || ng != g || nb != b) {
  1343.     r = nr;
  1344.     g = ng;
  1345.     b = nb;
  1346.     d = (nr-cr)*(nr-cr)+(ng-cg)*(ng-cg)+(nb-cb)*(nb-cb);
  1347.     for (each = 0; each<ct; each++) {
  1348.       if (d < cw->cpick.mdist[each]) {
  1349.         for (each2 = cw->cpick.nearpixels-1; each2>= each; each2--) {
  1350.           cw->cpick.nearcells[each2+1].red =
  1351.         cw->cpick.nearcells[each2].red;
  1352.           cw->cpick.nearcells[each2+1].green =
  1353.         cw->cpick.nearcells[each2].green;
  1354.           cw->cpick.nearcells[each2+1].blue =
  1355.         cw->cpick.nearcells[each2].blue;
  1356.           cw->cpick.mdist[each2+1] = cw->cpick.mdist[each2];
  1357.           strcpy(cw->cpick.mnames[each2+1], cw->cpick.mnames[each2]);
  1358.         }
  1359.         cw->cpick.nearcells[each].red = nr*RATIO;
  1360.         cw->cpick.nearcells[each].green = ng*RATIO;
  1361.         cw->cpick.nearcells[each].blue = nb*RATIO;
  1362.         cw->cpick.mdist[each] = d;
  1363.         strcpy(cw->cpick.mnames[each], sname);
  1364.         if (ct < cw->cpick.nearpixels) {
  1365.           ct++;
  1366.         }
  1367. #ifdef BUBBLE_MATCH
  1368.         XStoreColors(XtDisplay(cw), cw->cpick.cmap,
  1369.              &(cw->cpick.nearcells[each]),
  1370.              (int) (cw->cpick.nearpixels-each));
  1371. #endif
  1372.         break;
  1373.       }
  1374.     }
  1375.     if (ct < cw->cpick.nearpixels) {
  1376.       for (each2 = cw->cpick.nearpixels-1; each2>= ct; each2--) {
  1377.         cw->cpick.nearcells[each2+1].red =
  1378.           cw->cpick.nearcells[each2].red;
  1379.         cw->cpick.nearcells[each2+1].green =
  1380.           cw->cpick.nearcells[each2].green;
  1381.         cw->cpick.nearcells[each2+1].blue =
  1382.           cw->cpick.nearcells[each2].blue;
  1383.         cw->cpick.mdist[each2+1] = cw->cpick.mdist[each2];
  1384.         strcpy(cw->cpick.mnames[each2+1], cw->cpick.mnames[each2]);
  1385.       }
  1386.       cw->cpick.nearcells[ct].red = nr*RATIO;
  1387.       cw->cpick.nearcells[ct].green = ng*RATIO;
  1388.       cw->cpick.nearcells[ct].blue = nb*RATIO;
  1389.       cw->cpick.mdist[ct] = d;
  1390.       strcpy(cw->cpick.mnames[ct], sname);
  1391. #ifdef BUBBLE_MATCH
  1392.       XStoreColors(XtDisplay(cw), cw->cpick.cmap,
  1393.                &(cw->cpick.nearcells[ct]),
  1394.                (int) (cw->cpick.nearpixels-ct));
  1395. #endif
  1396.       ct++;
  1397.     }      
  1398.       }
  1399.     }
  1400.     if (ct != 0 &&
  1401.     cw->cpick.nearcells[0].red == cw->cpick.allocated->red &&
  1402.     cw->cpick.nearcells[0].green == cw->cpick.allocated->green &&
  1403.     cw->cpick.nearcells[0].blue == cw->cpick.allocated->blue) {
  1404.       setMlabelStr(cw, cw->cpick.mnames[0]);
  1405.     } else { 
  1406.       setMlabelStr(cw, NULLSTR);
  1407.     }
  1408.     fclose(fd);
  1409. #ifndef BUBBLE_MATCH
  1410.     XStoreColors(XtDisplay(cw), cw->cpick.cmap,
  1411.          cw->cpick.nearcells,
  1412.          (int) cw->cpick.nearpixels);
  1413. #endif
  1414.   }
  1415. }
  1416.  
  1417. static void setMlabelStr(cw, str)
  1418. CpickWidget cw;
  1419. char *str;
  1420. {
  1421.   XmString xs;
  1422.  
  1423.   xs = XmStringCreateSimple(str);
  1424.   count = 0;
  1425.   XtSetArg(args[count], XmNlabelString, xs);  count++;
  1426.   XtSetValues(cw->cpick.mlabel, args, count);
  1427.   XmStringFree(xs);
  1428. }
  1429.  
  1430. static createPalette(cw)
  1431. CpickWidget cw;
  1432. {
  1433.   count = 0;
  1434.   XtSetArg(args[count], XmNtopAttachment, XmATTACH_WIDGET);  count++;
  1435.   XtSetArg(args[count], XmNtopWidget, cw->cpick.boxButtons);  count++;
  1436.   XtSetArg(args[count], XmNtopOffset, INTER_SPACING); count++;
  1437.   XtSetArg(args[count], XmNleftAttachment, XmATTACH_WIDGET);  count++;
  1438.   XtSetArg(args[count], XmNleftWidget, cw->cpick.scaleSets);  count++;
  1439.   XtSetArg(args[count], XmNleftOffset, INTER_SPACING); count++;
  1440.   XtSetArg(args[count], XmNrightAttachment, XmATTACH_FORM);  count++;
  1441.   XtSetArg(args[count], XmNrightOffset, BORDER_MARGIN); count++;
  1442.   XtSetArg(args[count], XmNbottomAttachment, XmATTACH_WIDGET);  count++;
  1443.   XtSetArg(args[count], XmNbottomWidget, cw->cpick.mframe);  count++;
  1444.   XtSetArg(args[count], XmNbottomOffset, INTER_SPACING);  count++;
  1445.   cw->cpick.nlevel = XmCreateDrawingArea(cw->cpick.tlevel, "nlevel",
  1446.                      args, count);
  1447.   XtManageChild(cw->cpick.nlevel);
  1448.   XtAddCallback(cw->cpick.nlevel, XmNexposeCallback,
  1449.         (XtCallbackProc) nlevel_expose, (XtPointer) cw);
  1450.   cw->cpick.wide = RANGE;
  1451.   cw->cpick.keep = FALSE;
  1452.   cw->cpick.matched = FALSE;
  1453.  
  1454.   count = 0;
  1455.   XtSetArg(args[count], XmNbottomAttachment, XmATTACH_WIDGET);  count++;
  1456.   XtSetArg(args[count], XmNbottomWidget, cw->cpick.nlevel);  count++;
  1457.   XtSetArg(args[count], XmNbottomOffset, INTER_SPACING);  count++;
  1458.   XtSetValues(cw->cpick.bcontainer, args, count);
  1459. }
  1460.  
  1461. static void Initialize( request, new )
  1462.    Widget request;        /* what the client asked for */
  1463.    Widget new;            /* what we're going to give him */
  1464. {
  1465.   int each, depth;
  1466.  
  1467.   CpickWidget cw = (CpickWidget) new;
  1468.  
  1469.   if (!cw->cpick.cmap) {
  1470.     fprintf(stderr, "Cpick: Must set XmNcmap resource.\n");
  1471.     exit(1);
  1472.   } else if (cw->cpick.allocated == NULL) {
  1473.     fprintf(stderr, "Cpick: Must set XmNallocated resource.\n");
  1474.     exit(1);
  1475.   }
  1476.  
  1477.   count = 0;
  1478.   cw->cpick.tlevel = XmCreateForm(new, "form", args, count);
  1479.   XtManageChild(cw->cpick.tlevel);
  1480.  
  1481.   depth = XDisplayPlanes(XtDisplay(cw),
  1482.              XDefaultScreen(XtDisplay(cw)));
  1483.   cw->cpick.inc = INCREMENT;
  1484.   if (!cw->cpick.inc)
  1485.     cw->cpick.inc = 1;
  1486.  
  1487.   createScales(cw);
  1488.   createBox(cw);
  1489.   createCommands(cw);
  1490.   createPalette(cw);
  1491.  
  1492.   initPalette(cw);
  1493.  
  1494.   doNew(cw);
  1495.  
  1496.   if (cw->core.width == 0) {
  1497.     cw->core.width = 10;
  1498.   }
  1499.   if (cw->core.height == 0) {
  1500.     cw->core.height = 10;
  1501.   }
  1502. }
  1503.  
  1504. /**********************************************************************/
  1505.  
  1506. Widget
  1507. CpickGetBoxFrame(Widget w)
  1508. {
  1509.   CpickWidget cw = (CpickWidget) w;
  1510.  
  1511.   return cw->cpick.bframe;
  1512. }
  1513.